use crate::{
    error::ServerError,
    abstractions::{data::Data},
    protocol::type_schema::TypeSchema
};
use image::{DynamicImage, ImageBuffer, Rgba, codecs::png::PngEncoder, GenericImageView};
use serde_json::json;
use std::{fs::File, sync::{Arc, Mutex}};
use std::path::Path;
use base64::{Engine as _, engine::general_purpose::STANDARD as BASE64};
use web_view::*;
use std::process::Command;
use std::fs;
use std::io::Cursor;
use nalgebra::{SMatrix, SVector, DMatrix, DVector};

struct CalibrationState {
    points: Vec<(f32, f32)>,
    image_data: String,
    image_size: (u32, u32),
}

impl CalibrationState {
    fn new(video_path: &str) -> Result<Self, ServerError> {
        // 创建临时文件路径
        let temp_dir = std::env::temp_dir();
        let temp_image_path = temp_dir.join("first_frame.png");
        
        // 使用ffmpeg提取第一帧
        let output = Command::new("ffmpeg")
            .args([
                "-i", video_path,
                "-vframes", "1",
                "-q:v", "2",
                temp_image_path.to_str().unwrap()
            ])
            .output()
            .map_err(|e| ServerError::BuiltinTaskError(format!("无法执行ffmpeg命令: {}", e)))?;

        if !output.status.success() {
            let error = String::from_utf8_lossy(&output.stderr);
            return Err(ServerError::BuiltinTaskError(format!("ffmpeg执行失败: {}", error)));
        }

        // 读取生成的图像
        let image = image::open(&temp_image_path)
            .map_err(|e| ServerError::BuiltinTaskError(format!("无法打开提取的图像: {}", e)))?;
        
        let (width, height) = image.dimensions();

        // 转换为base64
        let mut buffer = Vec::new();
        let cursor = Cursor::new(&mut buffer);
        let encoder = PngEncoder::new(cursor);
        image.write_with_encoder(encoder)
            .map_err(|e| ServerError::BuiltinTaskError(format!("无法编码图像: {}", e)))?;
        let base64 = BASE64.encode(buffer);

        // 清理临时文件
        let _ = fs::remove_file(temp_image_path);

        Ok(Self {
            points: Vec::new(),
            image_data: format!("data:image/png;base64,{}", base64),
            image_size: (width, height),
        })
    }

    fn calculate_transform(&self) -> Result<serde_json::Value, ServerError> {
        if self.points.len() != 2 {
            return Err(ServerError::BuiltinTaskErrorStr("需要选择两个点"));
        }

        let (x1, y1) = self.points[0];
        let (x2, y2) = self.points[1];

        // 计算从原始坐标系到标准坐标系的变换
        let dx = x2 - x1;
        let dy = y2 - y1;
        let length = (dx * dx + dy * dy).sqrt();
        
        // 计算旋转角度
        let cos_theta = dx / length;
        let sin_theta = dy / length;

        // 构建变换矩阵
        let transform = json!({
            "matrix": [
                [cos_theta / length, -sin_theta / length, -x1 * cos_theta / length + y1 * sin_theta / length],
                [sin_theta / length, cos_theta / length, -x1 * sin_theta / length - y1 * cos_theta / length],
                [0.0, 0.0, 1.0]
            ],
            "description": "由两个点求得，从原始坐标系到标准坐标系的变换矩阵"
        });

        Ok(transform)
    }
}

/// builtin.calib_oc2p
/// itype: FilePath ::= Str
/// otype: CalibTransform ::= Json
pub fn calib_oc2p_func(input: Data) -> Result<Data, ServerError> {
    let path = input.as_string();
    let state = Arc::new(Mutex::new(CalibrationState::new(&path)?));
    let state_clone = state.clone();
    
    let result = Arc::new(Mutex::new(None));
    let result_clone = result.clone();

    // 读取HTML模板
    let html_template = include_str!("calibration.html");
    let html = html_template.replace("{IMAGE_DATA}", &state.lock().unwrap().image_data);

    let webview = web_view::builder()
        .title("标定工具")
        .content(Content::Html(html))
        .size(800, 600)
        .resizable(true)
        .debug(true)
        .user_data(())
        .invoke_handler(|webview, arg| {
            let points: Vec<Vec<f32>> = serde_json::from_str(arg).unwrap();
            
            let mut state = state_clone.lock().unwrap();
            state.points = points.into_iter()
                .map(|p| (p[0], p[1]))
                .collect();
            
            if let Ok(transform) = state.calculate_transform() {
                *result_clone.lock().unwrap() = Some(transform);
                webview.exit();
            }
            
            Ok(())
        })
        .build()
        .map_err(|e| ServerError::BuiltinTaskError(format!("无法创建webview: {}", e)))?;

    webview.run()
        .map_err(|e| ServerError::BuiltinTaskError(format!("webview运行错误: {}", e)))?;

    if let Some(transform) = result.lock().unwrap().take() {
        // 写入文件
        let file_path = "edp_files/system/transformation.json";
        let file = File::create(file_path).unwrap();
        serde_json::to_writer(file, &transform).unwrap();
        println!("变换矩阵matrix写入文件: {}", file_path);
        Ok(Data::DataJson(transform))
    } else {
        Err(ServerError::BuiltinTaskError("用户取消操作".to_string()))
    }
}

pub fn calib_les7p_func(input: Data) -> Result<Data, ServerError> {
    let path = input.as_string();
    let state = Arc::new(Mutex::new(CalibrationState::new(&path)?));
    let state_clone = state.clone();
    
    let result = Arc::new(Mutex::new(None));
    let result_clone = result.clone();

    // 读取HTML模板
    let html_template = include_str!("calibration.html");
    let html = html_template.replace("{IMAGE_DATA}", &state.lock().unwrap().image_data);

    println!("打开七点标定工具...");
    println!("请在图像上按顺序选择7个点：中心(0,0)、右(1,0)、右上(1/2,√3/2)、左上(-1/2,√3/2)、左(-1,0)、左下(-1/2,-√3/2)、右下(1/2,-√3/2)");
    println!("注意：从右侧开始按逆时针顺序选择六边形上的点");

    let webview = web_view::builder()
        .title("七点标定工具")
        .content(Content::Html(html))
        .size(800, 600)
        .resizable(true)
        .debug(true)
        .user_data(())
        .invoke_handler(|webview, arg| {
            let points: Vec<Vec<f32>> = serde_json::from_str(arg).unwrap();
            
            if points.len() != 7 {
                webview.eval(&format!("alert('请选择7个点，当前已选择{}个点')", points.len())).unwrap();
                return Ok(());
            }

            println!("收到7个点的坐标");
            let image_points: Vec<(f32, f32)> = points.into_iter()
                .map(|p| (p[0], p[1]))
                .collect();
            
            // 尝试计算相机矩阵
            println!("开始计算相机矩阵...");
            match calculate_camera_matrix(image_points) {
                Ok(transform) => {
                    println!("计算成功！");
                    *result_clone.lock().unwrap() = Some(transform);
                    webview.exit();
                },
                Err(e) => {
                    println!("计算失败: {}", e);
                    webview.eval(&format!("alert('计算失败: {}')", e)).unwrap();
                }
            }
            
            Ok(())
        })
        .build()
        .map_err(|e| ServerError::BuiltinTaskError(format!("无法创建webview: {}", e)))?;

    webview.run()
        .map_err(|e| ServerError::BuiltinTaskError(format!("webview运行错误: {}", e)))?;

    if let Some(transform) = result.lock().unwrap().take() {
        println!("变换矩阵计算完成，返回结果");
        // 写入文件
        let file_path = "edp_files/system/homography.json";
        let file = File::create(file_path).unwrap();
        serde_json::to_writer(file, &transform).unwrap();
        println!("单应性矩阵matrix写入文件: {}", file_path);
        Ok(Data::DataJson(transform))
    } else {
        println!("用户取消操作");
        Err(ServerError::BuiltinTaskError("用户取消操作".to_string()))
    }
}

// 计算七个点的相机矩阵
fn calculate_camera_matrix(image_points: Vec<(f32, f32)>) -> Result<serde_json::Value, String> {
    if image_points.len() != 7 {
        return Err("需要7个点".into());
    }

    // 标准世界坐标
    let world_points = [
        (0.0, 0.0),          // 中心点
        (1.0, 0.0),          // 右
        (0.5, 0.866),        // 右上 (1/2, sqrt(3)/2)
        (-0.5, 0.866),       // 左上 (-1/2, sqrt(3)/2)
        (-1.0, 0.0),         // 左
        (-0.5, -0.866),      // 左下 (-1/2, -sqrt(3)/2)
        (0.5, -0.866),       // 右下 (1/2, -sqrt(3)/2)
    ];

    // 对输入的点进行分类
    let center_point = find_center_point(&image_points)?;
    let mut sorted_points = sort_points_by_angle(&image_points, center_point)?;
    
    // 调整起始点，使得第一个点是最右侧的点
    let first_right_index = find_first_right_index(&sorted_points, center_point);
    if first_right_index > 0 {
        let mut rotated = Vec::new();
        rotated.extend_from_slice(&sorted_points[first_right_index..]);
        rotated.extend_from_slice(&sorted_points[0..first_right_index]);
        sorted_points = rotated;
    }

    // 为了使用全部7个点，我们使用构造正规方程求解最小二乘问题
    
    // 构建超定方程组 (14x8)，移除最后一列
    let n_points = 7;
    let mut a_matrix = DMatrix::<f32>::zeros(2 * n_points, 8);
    let mut b_vector = DVector::<f32>::zeros(2 * n_points);
    
    for i in 0..n_points {
        let (img_x, img_y) = sorted_points[i];
        let (world_x, world_y) = world_points[i];
        
        // 构建方程组的行（假设h33=1）
        a_matrix[(2*i, 0)] = img_x;
        a_matrix[(2*i, 1)] = img_y;
        a_matrix[(2*i, 2)] = 1.0;
        a_matrix[(2*i, 3)] = 0.0;
        a_matrix[(2*i, 4)] = 0.0;
        a_matrix[(2*i, 5)] = 0.0;
        a_matrix[(2*i, 6)] = -img_x * world_x;
        a_matrix[(2*i, 7)] = -img_y * world_x;
        
        a_matrix[(2*i+1, 0)] = 0.0;
        a_matrix[(2*i+1, 1)] = 0.0;
        a_matrix[(2*i+1, 2)] = 0.0;
        a_matrix[(2*i+1, 3)] = img_x;
        a_matrix[(2*i+1, 4)] = img_y;
        a_matrix[(2*i+1, 5)] = 1.0;
        a_matrix[(2*i+1, 6)] = -img_x * world_y;
        a_matrix[(2*i+1, 7)] = -img_y * world_y;
        
        b_vector[2*i] = world_x;
        b_vector[2*i+1] = world_y;
    }
    
    // 计算正规方程 A^T·A·x = A^T·b
    let at_a = &a_matrix.transpose() * &a_matrix;
    let at_b = &a_matrix.transpose() * &b_vector;
    
    // 求解正规方程
    let h_vector = match at_a.lu().solve(&at_b) {
        Some(solution) => solution,
        None => return Err("方程组求解失败，请重新选择点".into())
    };
    
    // 检查结果是否有NaN
    if h_vector.iter().any(|&val| val.is_nan() || !val.is_finite()) {
        return Err("计算结果包含无效值，请重新选择点".into());
    }
    
    // 构建单应性矩阵
    let matrix = vec![
        vec![h_vector[0], h_vector[1], h_vector[2]],
        vec![h_vector[3], h_vector[4], h_vector[5]],
        vec![h_vector[6], h_vector[7], 1.0]
    ];
    
    // 创建最终的JSON对象
    let homography = json!({
        "matrix": matrix,
        "description": "由七个点解线性方程组，从世界坐标到图像坐标的单应性矩阵matrix"
    });


    
    println!("计算完成，返回单应性矩阵matrix");
    Ok(homography)
}

// 找出中心点（离其它所有点平均距离最小的点）
fn find_center_point(points: &[(f32, f32)]) -> Result<(f32, f32), String> {
    if points.len() < 2 {
        return Err("至少需要2个点才能找到中心点".into());
    }

    let mut min_avg_distance = f32::MAX;
    let mut center = (0.0, 0.0);
    
    for &p1 in points {
        let mut total_distance = 0.0;
        let mut valid_points = 0;
        
        for &p2 in points {
            if p1 != p2 {
                let dx = p1.0 - p2.0;
                let dy = p1.1 - p2.1;
                let distance = (dx*dx + dy*dy).sqrt();
                
                if !distance.is_nan() && distance.is_finite() {
                    total_distance += distance;
                    valid_points += 1;
                }
            }
        }
        
        if valid_points > 0 {
            let avg_distance = total_distance / valid_points as f32;
            if avg_distance < min_avg_distance {
                min_avg_distance = avg_distance;
                center = p1;
            }
        }
    }
    
    if min_avg_distance == f32::MAX {
        return Err("无法找到有效的中心点".into());
    }
    
    Ok(center)
}

// 按照相对于中心点的角度排序其余点
fn sort_points_by_angle(points: &[(f32, f32)], center: (f32, f32)) -> Result<Vec<(f32, f32)>, String> {
    let mut sorted_points = vec![center]; // 第一个点是中心点
    
    // 收集除中心点外的所有点
    let mut other_points: Vec<_> = points.iter()
        .filter(|&&p| p != center)
        .cloned()
        .collect();
    
    if other_points.len() != 6 {
        return Err(format!("除中心点外应有6个点，实际有{}个", other_points.len()));
    }
    
    // 按角度排序
    other_points.sort_by(|a, b| {
        let angle_a = (a.1 - center.1).atan2(a.0 - center.0);
        let angle_b = (b.1 - center.1).atan2(b.0 - center.0);
        
        // 处理可能的NaN
        match (angle_a.is_nan(), angle_b.is_nan()) {
            (true, true) => std::cmp::Ordering::Equal,
            (true, false) => std::cmp::Ordering::Greater,
            (false, true) => std::cmp::Ordering::Less,
            (false, false) => angle_a.partial_cmp(&angle_b).unwrap_or(std::cmp::Ordering::Equal)
        }
    });
    
    sorted_points.extend(other_points);
    Ok(sorted_points)
}

// 找出最右侧的点的索引（相对于中心点，角度最接近0的点）
fn find_first_right_index(sorted_points: &[(f32, f32)], center: (f32, f32)) -> usize {
    let mut min_angle_diff = std::f32::consts::PI * 2.0;
    let mut right_index: usize = 1; // 从1开始，因为0是中心点
    
    for i in 1..sorted_points.len() {
        let dx = sorted_points[i].0 - center.0;
        let dy = sorted_points[i].1 - center.1;
        
        // 确保除数不为零
        if dx.abs() < f32::EPSILON && dy.abs() < f32::EPSILON {
            continue;
        }
        
        let angle = dy.atan2(dx);
        let angle_diff = angle.abs();
        
        if !angle_diff.is_nan() && angle_diff < min_angle_diff {
            min_angle_diff = angle_diff;
            right_index = i;
        }
    }
    
    right_index
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::abstractions::data::Data;
    
    #[test]
    fn test_calib_oc2p_func() {
        let path = r"C:\Users\songy\Desktop\fyp-songy-2025-04-27\videos\s,10,L,3-10.18downsampled.MOV";
        let input = Data::DataStr(path.to_string());
        let result = calib_oc2p_func(input);
        println!("{:?}", result);
    }

    #[test]
    fn test_calib_les7p_func() {
        let path = r"C:\Users\songy\Desktop\fyp-songy-2025-04-27\videos\s,10,L,3-10.18downsampled.MOV";
        let input = Data::DataStr(path.to_string());
        let result = calib_les7p_func(input);
        println!("{:?}", result);
    }
}
